package com.wsoft.core.utils;

import cn.afterturn.easypoi.word.WordExportUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.wsoft.constant.SessionConstant;
import com.wsoft.constant.WordConstant;
import org.apache.poi.xwpf.usermodel.*;
import org.jetbrains.annotations.NotNull;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * word 工具类
 * @Author z001
 * @Date 2024/11/14 13:09
 */
@Component
public class WordUtil  implements ApplicationContextAware {

    /**
     * 用于匹配占位符的正则表达式模式
     */
    private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");

    /**
     * Spring 应用上下文，用于获取 Spring Bean
     */
    private static ApplicationContext applicationContext;

    /**
     * 设置 Spring 应用上下文
     *
     * @param applicationContext Spring 应用上下文
     */
    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) {
        WordUtil.applicationContext = applicationContext;
    }

    /**
     * 处理 Word 模板文件，替换其中的占位符，并生成新的 Word 文件。
     *
     * @param templatePath 模板文件路径
     * @param outputPath   输出文件路径
     * @param params       动态传参的键值对
     * @throws IOException 如果文件读写过程中发生错误
     */
    public static void processTemplate(String templatePath, String outputPath, Map<String, Object> params) throws Exception {
        params.put(SessionConstant.CURRENT_USER,LoginUserUtil.getUserInfo().getLoginUserVO());
        XWPFDocument xwpfDocument = WordExportUtil.exportWord07(templatePath, params);
        FileInputStream inputStream = convertDocumentToFileInputStream(xwpfDocument);
        XWPFDocument document = new XWPFDocument(inputStream);

        // 替换文档中的占位符
        replacePlaceholders(document, params);

        // 将处理后的文档写入输出文件
        try (FileOutputStream fos = new FileOutputStream(outputPath)) {
            document.write(fos);
        }
    }

    /**
     * 替换文档中的所有占位符。
     *
     * @param document Word 文档对象
     * @param params   动态传参的键值对
     */
    private static void replacePlaceholders(XWPFDocument document, Map<String, Object> params) throws Exception {
        // 遍历文档中的所有段落
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            replacePlaceholdersInParagraph(paragraph, params);
        }

        // 遍历文档中的所有表格
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    // 遍历表格单元格中的所有段落
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replacePlaceholdersInParagraph(paragraph, params);
                    }
                }
            }
        }
    }

    /**
     * 替换段落中的所有占位符。
     *
     * @param paragraph 段落对象
     * @param params    动态传参的键值对
     */
    private static void replacePlaceholdersInParagraph(XWPFParagraph paragraph, Map<String, Object> params) throws Exception {

        // 合并段落中的所有文本运行
        StringBuilder paragraphText = new StringBuilder();
        for (XWPFRun run : paragraph.getRuns()) {
            String text = run.getText(0);
            if (text != null) {
                paragraphText.append(text);
            }
        }

        // 替换合并后的文本内容中的占位符
        String mergedText = paragraphText.toString();
        Matcher matcher = PLACEHOLDER_PATTERN.matcher(mergedText);
        StringBuilder newText = new StringBuilder();
        int lastIndex = 0;

        // 查找并替换所有占位符
        while (matcher.find()) {
            newText.append(mergedText, lastIndex, matcher.start());
            String placeholder = matcher.group(1);
            String replacement = getReplacement(placeholder, params);
            newText.append(replacement);
            lastIndex = matcher.end();
        }

        newText.append(mergedText.substring(lastIndex));

        // 将替换后的文本内容重新设置到段落中
        replaceParagraphText(paragraph, newText.toString());

    }

    /**
     * 清除段落文字 并替换
     * @param paragraph
     * @param newText
     */
    private static void replaceParagraphText(XWPFParagraph paragraph, String newText) {
        // 清除段落中的所有文本运行
        for (XWPFRun run : paragraph.getRuns()) {
            String text = run.getText(0);
            if (text != null) {
                run.setText("", 0);
            }
        }

        // 将替换后的文本内容重新设置到段落中
        XWPFRun run = paragraph.createRun();
        run.setText(newText, 0);
    }

    /**
     * 获取占位符的替换值。
     *
     * @param placeholder 占位符名称
     * @param params      动态传参的键值对
     * @return 替换值
     */
    private static String getReplacement(String placeholder, Map<String, Object> params) throws Exception {
        // 1. 检查是否是静态常量
        String handledConstant = handleConstant(placeholder);
        if(!handledConstant.equals(placeholder)){
            return handledConstant;
        }

        // 2. 检查是否是class
        if (placeholder.startsWith(WordConstant.CLASS_PREFIX)) {
            return handleClass(placeholder);
        }

        // 3. 检查是否是Spring Bean
        if (placeholder.startsWith(WordConstant.BEAN_PREFIX)) {
           return handleBean(placeholder);
        }


        // 3. 检查是否是动态传参
        if (params.containsKey(placeholder)) {
            return params.get(placeholder).toString();
        }

        // 4. 默认返回空字符串
        return "${" + placeholder + "}";
    }

    /**
     * 处理静态常量
     * @param placeholder
     * @return
     */
    private static String handleConstant(String placeholder){
        if (SessionConstant.CURRENT_USER_NAME.equals(placeholder)) {
            return LoginUserUtil.getUserInfo().getLoginUserVO().getName();
        }else if (SessionConstant.CURRENT_LOGIN_USER.equals(placeholder)) {
            return LoginUserUtil.getUserInfo().getLoginUserVO().getLoginName();
        } else if(SessionConstant.CURRENT_ORG.equals(placeholder)){
            return LoginUserUtil.getUserInfo().getLoginUserVO().getLoginOrgName();
        }else if(SessionConstant.CURRENT_POST.equals(placeholder)){
            return LoginUserUtil.getUserInfo().getLoginUserVO().getCurPostName();
        }else if(SessionConstant.CURRENT_LEVEL.equals(placeholder)){
            return  LoginUserUtil.getUserInfo().getLoginUserVO().getLevelName();
        }else if(SessionConstant.CURRENT_DATE.equals(placeholder)){
            return  DateUtil.format(new Date(), WordConstant.CURRENT_DATE_FORMAT);
        }else if(SessionConstant.CURRENT_DATE_TIME.equals(placeholder)){
            return  DateUtil.format(new Date(), WordConstant.CURRENT_DATE_TIME_FORMAT);
        }
        return placeholder;
    }

    /**
     * 处理全路径class
     * @param placeholder
     * @return
     */
    private static String handleClass(String placeholder) throws Exception {
        String contains ="(";
        if(placeholder.contains(contains)){
            //获取方法
            return parseAndExecuteMethod(placeholder);
        }else{
            //获取属性
            return parseAndGetField(placeholder).toString();
        }
    }

    /**
     * 处理bean
     * @param placeholder
     * @return
     */
    private static String handleBean(String placeholder){
        String[] parts = placeholder.split("\\.");
        int length = 2;
        if (parts.length >= length) {
            String beanName = parts[0].substring(5);
            String methodName = parts[1];
            Object bean = applicationContext.getBean(beanName);
            //执行方法
            String string = invokeMethod(methodName, bean,false, null);
            if(StrUtil.isNotBlank(string)){
                return string;
            }
        }
        return placeholder;
    }


    /**
     * 执行方法
     *
     * @param methodName
     * @param bean
     * @param clazz
     * @return
     */
    public static String invokeMethod(String methodName, Object bean, boolean isClass, Class<?> clazz){
        try {
            if (methodName.indexOf(WordConstant.METHOD_SUFFIX) > 0) {
                // 获取并调用方法
                Method method = bean.getClass().getMethod(methodName.replace("()", ""));
                Object result = method.invoke(bean);
                if (result != null) {
                    return result.toString();
                }
            }
            else {
                // 获取方法参数
                String[] paramParts = methodName.split("\\(");
                methodName = paramParts[0];
                Class<?>[] parameterTypes = new Class<?>[0];
                Object[] arguments = new Object[0];

                if (paramParts.length > 1) {
                    String[] paramValues = paramParts[1].replace(")", "").split(",");
                    parameterTypes = new Class<?>[paramValues.length];
                    arguments = new Object[paramValues.length];
                    for (int i = 0; i < paramValues.length; i++) {
                        String param = paramValues[i].trim();
                        if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_INT)) {
                            parameterTypes[i] = int.class;
                            arguments[i] = Integer.parseInt(param.substring(4));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_INTEGER)) {
                            parameterTypes[i] = Integer.class;
                            arguments[i] = Integer.parseInt(param.substring(8));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_DOUBLE_LOWER)) {
                            parameterTypes[i] = double.class;
                            arguments[i] = Double.valueOf(param.substring(7));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_DOUBLE_UPPER)) {
                            parameterTypes[i] = Double.class;
                            arguments[i] = Double.valueOf(param.substring(7));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_LONG_LOWER)) {
                            parameterTypes[i] = long.class;
                            arguments[i] = Long.valueOf(param.substring(5));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_LONG_UPPER)) {
                            parameterTypes[i] = Long.class;
                            arguments[i] = Long.valueOf(param.substring(5));
                        } else if (param.startsWith(WordConstant.METHOD_PARAM_TYPE_STRING_LOWER) || param.startsWith(WordConstant.METHOD_PARAM_TYPE_STRING_UPPER)) {
                            parameterTypes[i] = String.class;
                            arguments[i] = param.substring(7);
                        } else if (param.startsWith(WordConstant.BEAN_PREFIX)) {
                            String[] beanParts = param.split("\\.");
                            if (beanParts.length >= 2) {
                                String innerBeanName = beanParts[0].substring(5);
                                String innerMethodName = beanParts[1];
                                Object innerBean = applicationContext.getBean(innerBeanName);
                                Method innerMethod = innerBean.getClass().getMethod(innerMethodName);
                                arguments[i] = innerMethod.invoke(innerBean);
                                parameterTypes[i] = arguments[i].getClass();
                            }
                        } else {
                            parameterTypes[i] = String.class;
                            arguments[i] = param;
                        }
                    }
                }

                if(isClass){
                    // 3. 执行方法
                    Method method = clazz.getDeclaredMethod(methodName,parameterTypes);
                    Object result = method.invoke(bean, arguments);
                    if (result != null) {
                        return result.toString();
                    }
                }else{
                    // 获取并调用方法
                    Method method = bean.getClass().getMethod(methodName, parameterTypes);
                    Object result = method.invoke(bean, arguments);
                    if (result != null) {
                        return result.toString();
                    }
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解析字符串并获取方法
     * class:com.wsoft.constant.WordConstant.test()
     * @param placeholder
     * @return
     */
    public static String parseAndExecuteMethod(String placeholder) throws Exception{
        int lastDotIndex = placeholder.lastIndexOf(StrUtil.DOT);
        if (lastDotIndex == -1) {
            return placeholder;
        }

        //提取方法名
        String methodName = placeholder.substring(lastDotIndex + 1);
        //提取类名
        String allPath = placeholder.substring(0, lastDotIndex);
        String[] split = allPath.split(StrUtil.COLON);
        int length = 2;
        if (split.length < length) {
            return placeholder;
        }
        String className = split[1];
        Class<?> clazz = Class.forName(className);

        // 2. 创建类的实例
        Object instance = clazz.getDeclaredConstructor().newInstance();

        String result = invokeMethod(methodName, instance,true,clazz);
        if(StrUtil.isNotBlank(result)){
            return result;
        }

        return placeholder;
    }

    /**
     * 解析字符串并获取静态字段
     *
     * @param placeholder 输入字符串，格式为 "class:com.wsoft.constant.CommonConstant.UPLOAD_TYPE_LOCAL"
     * @return 静态字段的值
     * @throws Exception 如果解析或获取字段失败
     */
    public static Object parseAndGetField(String placeholder) throws Exception {
        // 1. 解析字符串
        String[] parts = placeholder.split(StrUtil.COLON);
        int length = 2;
        if (parts.length < length) {
            return placeholder;
        }

        // 2. 获取类名和字段名
        // 1. 找到最后一个 "." 的位置
        int lastDotIndex = parts[1].lastIndexOf(".");

        // 2. 如果找不到 "."，抛出异常
        if (lastDotIndex == -1) {
            return placeholder;
        }

        // 3. 提取类名和属性名
        String className = parts[1].substring(0, lastDotIndex);
        String fieldName = parts[1].substring(lastDotIndex + 1);

        // 3. 获取类对象
        Class<?> clazz = Class.forName(className);

        // 4. 获取静态字段
        Field field = clazz.getDeclaredField(fieldName);
        // 确保可以访问私有字段
        field.setAccessible(true);

        // 5. 返回字段值
        // 静态字段不需要实例，传入 null
        return field.get(null);
    }

    private static FileInputStream convertDocumentToFileInputStream(XWPFDocument document) throws IOException {
        // 创建临时文件
        File tempFile = File.createTempFile("temp_document", ".docx");
        tempFile.deleteOnExit(); // 确保程序退出时删除临时文件

        // 将 XWPFDocument 写入临时文件
        try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            document.write(fos);
        }

        // 返回 FileInputStream
        return new FileInputStream(tempFile);
    }


    public static void main(String[] args) {
        String format = DateUtil.format(new Date(), "yyyy-MM-dd");
        String format1 = DateUtil.format(new Date(), "yyyy/MM/dd HH:mm:ss");
        System.out.println(format);
        System.out.println(format1);
    }

}
